﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using System.Text.RegularExpressions;
using GoogleTranslationApiServices;
using System.IO;
using System.Net;
using Localization.Repository;
using Localization.Repository.Models;
using log4net;
using System.Configuration;

namespace LocalizationEditor
{
    /// <summary>
    /// 
    /// <see cref="http://msdn.microsoft.com/en-us/library/aa905797.aspx"/>
    /// <see cref="http://msdn.microsoft.com/en-us/library/sb6a8618(v=VS.90).aspx">This describes the usage of satellite assemblies for .net 2.0 and higher</see>
    /// <see cref="http://msdn.microsoft.com/en-us/library/21a15yht%28VS.90%29.aspx"></see>
    /// </summary>
    public partial class ResourceViewer : Form
    {
        private ILog log = LogManager.GetLogger(typeof(ResourceViewer));

        private ResourceRepository Repository { get; set; }
        private string lastAccessedDirectory = Environment.CurrentDirectory;

        private ITranslatorService _translatorService;
        public ITranslatorService TranslatorService
        {
            get
            {
                if (_translatorService == null)
                    _translatorService = new GoogleTranslatorService();
                return _translatorService;
            }
            set { _translatorService = value; }
        }

        public ResourceViewer()
        {
            InitializeComponent();

            this.dgvResourceValues.AutoGenerateColumns = false;

            // tool tip init
            toolTip.SetToolTip(this.listBoxClassKeys, "Class Keys");
        }

        private void ShowSearchTab()
        {
            return;
            if (this.comboBoxClassKey.Items.Count > 0
                && this.comboBoxCultures.Items.Count > 0)
            {
                this.tabSearchResources.Show();
            }
            else
            {
                if (this.comboBoxCultures.Items.Count == 0)
                    this.tabCultures.Focus();
                if (this.comboBoxClassKey.Items.Count == 0)
                    this.tabClassKeys.Focus();

                this.tabSearchResources.Hide();
            }
        }

        #region Resources Tab

        private bool _isSearchUsingDefaultCulture;

        /// <summary>
        /// Gets the selected resource class key.
        /// Returns null is all or none is selected.
        /// </summary>
        /// <value>The selected resource class key.</value>
        private ResourceClassKey ResourceClassKeySelected
        {
            get
            {
                object classKey = comboBoxClassKey.SelectedItem;
                if (classKey != null)
                    return (ResourceClassKey)classKey;
                return null;
            }
        }

        private CultureInfo ResourceCulturesSelected
        {
            get
            {
                object ci = comboBoxCultures.SelectedItem;
                if (ci != null)
                    return (CultureInfo)ci;
                return null;
            }
        }

        private void LoadSearchPane()
        {
            dgvResourceValues.AutoGenerateColumns = false;

            // get search conditions
            ResourceClassKey classKey = ResourceClassKeySelected;
            string classKeyName = classKey == null ? null : classKey.ClassKeyName;
            CultureInfo ci = ResourceCulturesSelected;

            if (ci == null)
            {
                MessageBox.Show(
                    this,
                    "There are no cultures defined yet.  Add a culture before creating resources.",
                    "Cultures Not Defined",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Information);
                this.tabControl.SelectedTab = this.tabCultures;
                return;
            }

            string keyword = textBoxKeyword.Text;

            IEnumerable<ResourceValue> values = Repository.SearchResourceText(
                keyword,
                checkBoxSearchBeginsWith.Checked,
                classKeyName,
                ci);

            // if culutre searched for is default then make context editable
            this._isSearchUsingDefaultCulture = ci.Name == Repository.GetDefaultCulture().Name;

            if (this._isSearchUsingDefaultCulture)
            {
                dgvResourceValues.AllowUserToAddRows = true;
                this.groupBoxAddResource.Enabled = true;
            }
            else
            {
                dgvResourceValues.AllowUserToAddRows = false;
                dgvResourceValues.Columns[0].ReadOnly = true;
                this.groupBoxAddResource.Enabled = false;
            }

            // get data
            IList<ResourceValue> list = values.ToList();
            dgvResourceValues.DataSource = list;

            for (int i = 0; i < list.Count; i++)
            {
                if (list[i].IsTranslated)
                    continue;

                dgvResourceValues.Rows[i].DefaultCellStyle.BackColor = Color.LemonChiffon;
            }
        }

        private void buttonSearch_Click(object sender, EventArgs e)
        {
            LoadSearchPane();
        }

        private void buttonAddResource_Click(object sender, EventArgs e)
        {
            string name = this.textBoxName.Text;
            string value = this.textBoxValue.Text;
            string comment = this.textBoxComment.Text;
            string classKey = ResourceClassKeySelected.ClassKeyName;

            IEnumerable<ResourceValue> values = Repository.SearchResourceText(
                value,
                true,
                classKey,
                Repository.GetDefaultCulture().GetCultureFromName());

            foreach (ResourceValue r in values)
                if (r.Value == value)
                {
                    DialogResult result = MessageBox.Show(
                        this,
                        "Resource already exists with this value, continue anyway?",
                        "Resource Exists",
                        MessageBoxButtons.YesNo,
                        MessageBoxIcon.Question);
                    return;
                }

            try
            {
                Repository.AddResource(
                    name,
                    value,
                    classKey,
                    comment);

                this.textBoxComment.Text = string.Empty;
                this.textBoxName.Text = string.Empty;
                this.textBoxValue.Text = string.Empty;
                this.textBoxName.Select();
            }
            catch (Exception x)
            {
                MessageBox.Show(this,
                    x.Message,
                    "Error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }

            LoadSearchPane();
        }

        private void dataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (this.dgvResourceValues.CurrentRow.Index < 0)
                return;
            DataGridViewRow row = dgvResourceValues.Rows[e.RowIndex];
            this.textBoxSelectedResValue.Text = row.Cells[1].Value as string;
        }

        private void dgvResourceValues_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            DataGridViewRow row = dgvResourceValues.Rows[e.RowIndex];
            if (row.IsNewRow)
                return;
            string name = row.Cells[1].Value as string;
            string value = row.Cells[2].Value as string;
            string comment = row.Cells[3].Value as string;
            if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value))
                return;

            string classKey = ResourceClassKeySelected.ClassKeyName;

            if (this._isSearchUsingDefaultCulture)
            {
                Repository.ModifyDefaultCulture(
                    name,
                    value,
                    comment,
                    classKey);
            }
            else
            {
                Repository.Translate(name, value, classKey, this.ResourceCulturesSelected);
                row.Cells[0].Value = true;
            }
        }

        private void comboBoxCultures_SelectedIndexChanged(object sender, EventArgs e)
        {
            ResourceCulture c = Repository.GetDefaultCulture();
            if (c != null)
            {
                if (ResourceCulturesSelected.Name == Repository.GetDefaultCulture().Name)
                {
                    this._isSearchUsingDefaultCulture = true;
                    labelSearchCulture.ForeColor = Color.Red;
                    dgvResourceValues.AllowUserToDeleteRows = true;
                }
                else
                {
                    this._isSearchUsingDefaultCulture = false;
                    labelSearchCulture.ForeColor = Color.Black;
                    dgvResourceValues.AllowUserToDeleteRows = false;
                }
            }
        }

        #endregion

        #region Cultures Tab

        private void LoadUsedCultures()
        {
            // get used cultures
            List<CultureInfo> usedCultures = new List<CultureInfo>();
            foreach (var c in Repository.GetCultures())
                usedCultures.Add(c.GetCultureFromName());

            // all cultures available
            CultureInfo[] allCultures = CultureInfo.GetCultures(CultureTypes.AllCultures);

            // get unused ones
            IList<CultureInfo> notUsedCultures =
                (from c in allCultures
                 where !usedCultures.Contains(c) && c.Name != string.Empty
                 orderby c.DisplayName ascending
                 select c).ToList<CultureInfo>();

            // set data source of boxes
            this.listBoxUsingCI.DataSource = usedCultures;
            this.comboBoxCultures.DataSource = usedCultures;
            this.listBoxAvailableCI.DataSource = notUsedCultures;

        }

        private void buttonAddCulture_Click(object sender, EventArgs e)
        {
            // get selected culture
            CultureInfo ci = this.listBoxAvailableCI.SelectedItem as CultureInfo;
            if (ci != null)
            {
                bool isDefault = false;
                // if there are no cultures used yet prompt to default
                if (Repository.GetCultures().Count() == 0)
                {
                    DialogResult result = MessageBox.Show("The first culture added will be the default.",
                        "Create Default",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information);
                    isDefault = true;
                }

                Repository.AddNewCulture(ci, isDefault);

                // reload necessary items
                LoadUsedCultures();
                ShowSearchTab();

                return;
            }
            MessageBox.Show("A culture was not selected.");
        }

        private void buttonRemoveCulture_Click(object sender, EventArgs e)
        {
            // get selected culture
            CultureInfo ci = this.listBoxUsingCI.SelectedItem as CultureInfo;
            if (ci != null)
            {
                // verify it's not the default culture
                ResourceCulture defaultCI = Repository.GetDefaultCulture();
                if (0 != string.Compare(defaultCI.Name, ci.Name, true))
                {
                    MessageBox.Show(this, "Cannot remove default culutre.");
                    return;
                }

                LoadUsedCultures();
            }
        }

        private void listBoxUsingCI_SizeChanged(object sender, EventArgs e)
        {
            EnableResourceButtons();
        }

        #endregion

        #region Class Keys Tab

        private int _editingClassKeyId;

        private void LoadClassKeys()
        {
            IEnumerable<ResourceClassKey> classKeys = Repository.GetClassKeys();
            //foreach (ResourceClassKey k in classKeys)
            //{
            //    DataGridViewRow row = new DataGridViewRow();
            //    row.CreateCells(this.dgvClassKeys, new object[] { k.ClassKeyName });
            //    row.Tag = k.ID;
            //    this.dgvClassKeys.Rows.Add(row);
            //}

            this.listBoxClassKeys.DataSource = classKeys;
            this.comboBoxClassKey.DataSource = classKeys;

            EnableResourceButtons();
        }

        private void buttonClassKeyAdd_Click(object sender, EventArgs e)
        {
            string name = this.textBoxClassKeyName.Text;
            if (string.IsNullOrEmpty(name))
                return;

            if (this._editingClassKeyId > 0)
            {
                ResourceClassKey ck = new ResourceClassKey
                {
                    ResourceClassKeyID = this._editingClassKeyId,
                    ClassKeyName = name
                };
                Repository.ModifyClassKey(ck);

                MessageBox.Show(
                    this,
                    "Resource class key has been changed to : " + name,
                    "Success",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Information);

                // call cancel to reset buttons
                this.buttonClassKeyCancel_Click(sender, e);
            }
            else
            {
                try
                {
                    ResourceClassKey newClassKey = new ResourceClassKey
                    {
                        ClassKeyName = name
                    };
                    Repository.AddClassKey(newClassKey);
                }
                catch (Exception x)
                {
                    MessageBox.Show(this,
                        "Unable to create class key.  Error: " + x.Message,
                        "Error",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
                    return;
                }
            }

            // refresh list
            LoadClassKeys();
        }

        private void buttonClassKeyCancel_Click(object sender, EventArgs e)
        {
            this.textBoxClassKeyName.Text = string.Empty;
            this.buttonClassKeyAdd.Text = "Add";
            this.buttonClassKeyCancel.Visible = false;
            this._editingClassKeyId = -1;
        }

        private void listBoxClassKeys_DoubleClick(object sender, EventArgs e)
        {
            ResourceClassKey ck = this.listBoxClassKeys.SelectedItem as ResourceClassKey;
            if (ck == null)
            {
                MessageBox.Show(
                    this,
                    "Class key could not be found.  Reloading list.",
                    "Reload",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Information);

                LoadClassKeys();
                return;
            }

            this._editingClassKeyId = ck.ResourceClassKeyID;
            this.textBoxClassKeyName.Text = ck.ClassKeyName;
            this.buttonClassKeyAdd.Text = "Save";
            this.buttonClassKeyCancel.Visible = true;
        }

        #endregion

        private void ResourceViewer_Shown(object sender, EventArgs e)
        {
            // if show first message is true then show user intro message
            bool showMessage = false;
            if (bool.TryParse(ConfigurationManager.AppSettings["showFirstUseMessage"], out showMessage) && showMessage)
            {
                FirstMessageForm msgForm = new FirstMessageForm();
                msgForm.ShowDialog(this);
            }
        }

        /// <summary>
        /// Enables the resource buttons which are dependent on 
        /// having at least 1 culture and 1 resource class key.
        /// </summary>
        /// 
        private void EnableResourceButtons()
        {
            this.translateWithGoogleToolStripMenuItem.Enabled =
                this.generateResourceFilesToolStripMenuItem.Enabled =
                this.buttonAddResource.Enabled =
                (this.listBoxAvailableCI.Items.Count > 0 && this.listBoxClassKeys.Items.Count > 0);
        }

        private void buttonDeleteResKey_Click(object sender, EventArgs e)
        {
            if (!this._isSearchUsingDefaultCulture)
            {
                MessageBox.Show(this, "Deletion of resources can only be done when default culture is selected.");
                return;
            }

            bool reloadSearch = false;

            for (int i = 0; i < dgvResourceValues.Rows.Count; i++)
            {
                DataGridViewCheckBoxCell cell = (DataGridViewCheckBoxCell)dgvResourceValues.Rows[i].Cells[0];

                if ((bool)cell.EditedFormattedValue)
                {
                    reloadSearch = true;

                    ResourceValue value = dgvResourceValues.Rows[i].DataBoundItem as ResourceValue;

                    log.Info(string.Format("Resource key [{0}] for class [{1}] was removed.",
                        value.ResourceKey.Name, value.ClassKeyName));

                    try
                    {
                        Repository.RemoveResourceKey(value.ResourceKey.Name, value.ClassKeyName);
                    }
                    catch (Exception x)
                    {
                        string message = string.Format("Unable to remove resource keys.");
                        log.Error(message, x);
                        MessageBox.Show(
                            this,
                            message,
                            "Error",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error);

                        log.Error(string.Format("Error removing resource key [{0}] for class [{1}].",
                        value.ResourceKey.Name, value.ClassKeyName), x);

                        break;
                    }
                }

            }

            // reload search pain
            if (reloadSearch)
                LoadSearchPane();
        }

        private void languageListFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GenerateResourceFiles(ResourceFileType.Android_LanguageFile);
        }

        private void LoadAllForms()
        {
            LoadClassKeys();
            LoadUsedCultures();
            ShowSearchTab();
            EnableResourceButtons();
            LoadSearchPane();   // should we do this ???
        }

        #region Menu

        #region File

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FileDialog dialog = new OpenFileDialog();
            dialog.Filter = "Data file (*.sdf)|*.sdf";
            dialog.DefaultExt = "sdf";
            dialog.InitialDirectory = lastAccessedDirectory;
            DialogResult dResult = dialog.ShowDialog(this);
            if (dResult == System.Windows.Forms.DialogResult.OK)
            {
                try
                {
                    Repository = new ResourceRepository(dialog.FileName);
                    LoadAllForms();

                    tabControl.Enabled = true;
                }
                catch (Exception x)
                {
                    MessageBox.Show(x.Message);
                }
            }
        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            dialog.ShowNewFolderButton = false;
            dialog.SelectedPath = lastAccessedDirectory;
            DialogResult dResult = dialog.ShowDialog(this);
            if (dResult == System.Windows.Forms.DialogResult.OK)
            {
                lastAccessedDirectory = dialog.SelectedPath;

                try
                {
                    Repository = new ResourceRepository(dialog.SelectedPath, "Resources");
                    LoadAllForms();

                    tabControl.Enabled = true;
                }
                catch (Exception x)
                {
                    MessageBox.Show(x.Message);
                }
            }
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Repository.Dispose();

            // disable tabs
            tabControl.Enabled = false;
        }

        #region Generate res files

        private void resourceFilesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GenerateResourceFiles(ResourceFileType.Android_ResourceFiles);
        }

        private void GenerateResourceFiles(ResourceFileType fileType)
        {
            try
            {
                string outputFolder = "Resources";
                // see if dir exists
                if (!Directory.Exists(outputFolder))
                    Directory.CreateDirectory(outputFolder);

                FolderBrowserDialog fb = new FolderBrowserDialog();
                fb.ShowNewFolderButton = false;
                fb.SelectedPath = Environment.CurrentDirectory + "\\" + outputFolder;
                DialogResult dResult = fb.ShowDialog(this);
                if (dResult == System.Windows.Forms.DialogResult.OK)
                    outputFolder = fb.SelectedPath;

                ResourceClassKey classKey = ResourceClassKeySelected;
                Repository.GenereateResourceFiles(classKey.ClassKeyName, outputFolder, fileType);

                MessageBox.Show(
                    this,
                    "Resource files have been built to: " + outputFolder,
                    "Success",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Information);
            }
            catch (Exception x)
            {
                MessageBox.Show(
                    this,
                    "Error while generating resource files.  Message: " + x.Message,
                    "Error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }

        private void buttonGenResourceFile_Click(object sender, EventArgs e)
        {
            GenerateResourceFiles(ResourceFileType.DotNet_Resource);
        }

        private void buttonGenResXFile_Click(object sender, EventArgs e)
        {
            GenerateResourceFiles(ResourceFileType.DotNet_ResX);
        }

        #endregion

        #endregion

        #region Tools

        #region Google Translate

        private void aPIKeyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // open api key form
            GoogleApiKeyForm form = new GoogleApiKeyForm();
            form.Owner = this;
            form.ShowDialog(this);
        }

        private void TranslateCultures(IEnumerable<CultureInfo> cultures)
        {
            CultureInfo defaultCulture = Repository.GetDefaultCulture().GetCultureFromName();

            try
            {
                foreach (ResourceClassKey classKey in Repository.GetClassKeys())
                {
                    foreach (CultureInfo ci in cultures)
                    {
                        if (ci.Name == defaultCulture.Name)
                            continue;

                        IEnumerable<ResourceValue> untranslated = Repository.UnTranslatedValues(classKey.ClassKeyName, ci);
                        foreach (ResourceValue r in untranslated)
                        {
                            try
                            {
                                string translation = TranslatorService.Translate(
                                    r.Value,
                                    defaultCulture,
                                    ci);

                                // save translation
                                Repository.Translate(r.Name, translation, classKey.ClassKeyName, ci);
                            }
                            catch (WebException webX)
                            {
                                MessageBox.Show(
                                    this,
                                    "Google services were not available.  Error: " + webX.Message,
                                    "Services Unavailable",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Warning);
                                return;
                            }
                            catch (Exception x)
                            {
                                if (x.Message.Contains("Unsupported culture"))
                                {
                                    MessageBox.Show(
                                        this,
                                        string.Format("[{0}] is an unsupported culture.", ci.DisplayName),
                                        "Unsupported",
                                        MessageBoxButtons.OK,
                                        MessageBoxIcon.Warning);

                                    break;
                                }
                                MessageBox.Show(x.Message);
                            }
                        }
                    }
                }
            }
            catch (Exception x)
            {
                MessageBox.Show(x.Message);
            }
        }

        private void buttonGoogleTranslate_Click(object sender, EventArgs e)
        {
            List<CultureInfo> cultures = new List<CultureInfo>();
            foreach (ResourceCulture rc in Repository.GetCultures())
                cultures.Add(rc.GetCultureFromName());

            this.TranslateCultures(cultures);

            // invoke search event to reset search
            buttonSearch_Click(sender, e);
        }

        #endregion

        #endregion

        #endregion
    }
}
